#ifdef DEBUG
#include <iostream>
#endif
#include <cctype>
#include "png2ico_window.h"
#include "file_list.h"
#include "utils.h"
#include "options_dialog.h"
#include "about_dialog.h"

Png2IcoWindow::Png2IcoWindow ()
  : dirBrowseBtn_("..."), outputBrowseBtn_("..."), convertBtn_("Convert"), vBox_(false), 
    treeVBox_(true), dirLbl_("PNG File Directory:"), outputLbl_("Output Directory:"),
    filenameLbl_("Filename:"), table_(3, 3, false)
{
  set_title ("PNG to ICO Converter");
  treeView_.set_size_request (300, 250);
  dirEntry_.set_editable (false);
  dirEntry_.set_size_request (300, 22);
  dirBrowseBtn_.set_tooltip_text ("Browse for directory containing PNG files");
  outputEntry_.set_editable (false);
  outputEntry_.set_size_request (300, 22);
  filenameEntry_.set_size_request (300, 22);
  filenameEntry_.set_tooltip_text ("Name of icon file to be written");
  dirBrowseBtn_.set_size_request (23, 10);
  outputBrowseBtn_.set_size_request (23, 10);
  outputBrowseBtn_.set_tooltip_text ("Browse for output directory");
  convertBtn_.set_tooltip_text ("Converts the PNG file(s) to an icon file");

  dirEntry_.modify_base (Gtk::STATE_NORMAL, Gdk::Color ("gray"));
  dirEntry_.modify_bg (Gtk::STATE_NORMAL, Gdk::Color ("gray"));
  outputEntry_.modify_base (Gtk::STATE_NORMAL, Gdk::Color ("gray"));
  outputEntry_.modify_bg (Gtk::STATE_NORMAL, Gdk::Color ("gray"));

  convertBtn_.signal_clicked ().connect (sigc::mem_fun (*this,
                                                        &Png2IcoWindow::on_convert_button_clicked));
  dirBrowseBtn_.signal_clicked ().connect (sigc::mem_fun (*this,
                                                          &Png2IcoWindow::on_dir_browse_button_clicked));
  outputBrowseBtn_.signal_clicked ().connect (sigc::mem_fun (*this,
                                                             &Png2IcoWindow::on_output_browse_button_clicked));
  filenameEntry_.signal_focus_out_event ().connect (sigc::mem_fun (*this,
                                                                   &Png2IcoWindow::on_focus_out_event));


  add (vBox_);

  // ---------------------------------------------------------------

  refActionGroup_ = Gtk::ActionGroup::create();
  refActionGroup_->add(Gtk::Action::create("FileMenu", "File"));
  refActionGroup_->add(Gtk::Action::create("FileNew", Gtk::Stock::NEW));
  refActionGroup_->add(Gtk::Action::create("FileQuit", Gtk::Stock::QUIT),
                       sigc::mem_fun(*this, &Png2IcoWindow::on_menu_file_quit));
  refActionGroup_->add(Gtk::Action::create("EditMenu", "Edit"));
  refActionGroup_->add(Gtk::Action::create("EditOptions", "Options"),
                       Gtk::AccelKey("<control>O"),
                       sigc::mem_fun(*this, &Png2IcoWindow::on_menu_edit_options));
  refActionGroup_->add( Gtk::Action::create("HelpMenu", "Help") );
  refActionGroup_->add( Gtk::Action::create("HelpAbout", Gtk::Stock::HELP),
                        sigc::mem_fun(*this, &Png2IcoWindow::on_menu_help_about));
  refUIManager_ = Gtk::UIManager::create();
  refUIManager_->insert_action_group(refActionGroup_);
  add_accel_group(refUIManager_->get_accel_group());

  // Layout the actions in a menubar
  Glib::ustring ui_info = 
    "<ui>"
    "  <menubar name='MenuBar'>"
    "    <menu action='FileMenu'>"
    "      <separator/>"
    "      <menuitem action='FileQuit'/>"
    "    </menu>"
    "    <menu action='EditMenu'>"
    "      <menuitem action='EditOptions'/>"
    "    </menu>"
    "    <menu action='HelpMenu'>"
    "      <menuitem action='HelpAbout'/>"
    "    </menu>"
    "  </menubar>"
    "</ui>";

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  try
    {
      refUIManager_->add_ui_from_string(ui_info);
    }
  catch(const Glib::Error& ex)
    {
      std::cerr << "building menus failed: " <<  ex.what();
    }
#else
  std::auto_ptr<Glib::Error> ex;
  refUIManager_->add_ui_from_string(ui_info, ex);
  if(ex.get())
    {
      std::cerr << "building menus failed: " <<  ex->what();
    }
#endif //GLIBMM_EXCEPTIONS_ENABLED

  // add the menubar to a container widget
  Gtk::Widget* pMenubar = refUIManager_->get_widget("/MenuBar");
  if(pMenubar)
    vBox_.pack_start(*pMenubar, Gtk::PACK_SHRINK);

  // ---------------------------------------------------------------

  vBox_.pack_start (table_);
  table_.set_row_spacing (0, 5);
  table_.set_row_spacing (1, 5);
  table_.set_border_width (10);

  table_.attach (dirLbl_, 0, 1, 0, 1);
  table_.attach (dirEntry_, 1, 2, 0, 1);
  table_.attach (dirBrowseBtn_, 2, 3, 0, 1);

  table_.attach (outputLbl_, 0, 1, 1, 2);
  table_.attach (outputEntry_, 1, 2, 1, 2);  
  table_.attach (outputBrowseBtn_, 2, 3, 1, 2);

  table_.attach (filenameLbl_, 0, 1, 2, 3);
  table_.attach (filenameEntry_, 1, 2, 2, 3);

  scrolledWindow_.add (treeView_);
  scrolledWindow_.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
  treeVBox_.pack_start (scrolledWindow_);
  vBox_.pack_start (treeVBox_);

  refTreeModel_ = Gtk::ListStore::create (columns_);
  treeView_.set_model (refTreeModel_);

  treeView_.append_column_editable (" Use ", columns_.col_use);
  treeView_.append_column (" PNG Filename ", columns_.col_filename);

  vBox_.pack_start (buttonBox_);
  buttonBox_.set_border_width (5);
  buttonBox_.pack_start (convertBtn_, Gtk::PACK_SHRINK);
  //buttonBox_.set_layout (Gtk::BUTTONBOX_END);

  show_all_children();
  filenameEntry_.grab_focus ();
}

Png2IcoWindow::~Png2IcoWindow ()
{

}

void Png2IcoWindow::on_menu_file_quit ()
{
  hide ();
}

void Png2IcoWindow::on_menu_edit_options ()
{
  OptionsDialog options;
  options.showDialog ();
}

void Png2IcoWindow::on_dir_browse_button_clicked()
{
  doBrowseFolder (PNG_DIR);
  if (!dirEntry_.get_text ().empty ())
    {
      typedef Gtk::TreeModel::Children type_children;
      type_children children = refTreeModel_->children();
      refTreeModel_->clear ();
#ifdef DEBUG
      std::cout << "directory: " << dirEntry_.get_text () << std::endl;
#endif // DEBUG
      FileList fl = FileList (dirEntry_.get_text ().c_str ());
      vector<std::string> files = fl.getFiles ();
      size_t found;
      Gtk::TreeModel::Row row;
      int i = 0;
      for (vector<std::string>::iterator iter=files.begin (); iter != files.end (); iter++)
        {
          std::string tmp = *iter;
          transform (tmp.begin (), tmp.end (), tmp.begin (), tolower);
          found = tmp.find (".png");
          if (found != std::string::npos)
            {
#ifdef DEBUG
              std::cout << "adding file: " << iter->c_str () << std::endl;
#endif // DEBUG
              row = *(refTreeModel_->append ());
              row[columns_.col_use] = false;
              row[columns_.col_filename] = iter->c_str ();
              i++;
            }
        }
    }
}

void Png2IcoWindow::on_output_browse_button_clicked()
{
  doBrowseFolder (OUTPUT_DIR);
}

void Png2IcoWindow::doBrowseFolder (DIRECTORY_TYPE dirType)
{
  Gtk::FileChooserDialog dialog("Please choose a folder",
                                Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
  dialog.set_transient_for(*this);

  dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
  dialog.add_button("Select", Gtk::RESPONSE_OK);

  int result = dialog.run();

  switch(result)
    {
    case(Gtk::RESPONSE_OK):
      {
#ifdef DEBUG
        std::cout << "Select clicked." << std::endl;
        std::cout << "Folder selected: " << dialog.get_filename() << std::endl;
#endif // DEBUG
        if (dirType == PNG_DIR)
          {
#ifdef __MINGW32__
            std::string s = dialog.get_filename ().c_str ();
            Utils::replaceAll (s, "\\", "/");
            dirEntry_.set_text (s);
#else
            dirEntry_.set_text (dialog.get_filename());
#endif // __MINGW32__
          }
        else
          {
#ifdef __MINGW32__
            std::string s = dialog.get_filename ().c_str ();
            Utils::replaceAll (s, "\\", "/");
            outputEntry_.set_text (s);
#else
            outputEntry_.set_text (dialog.get_filename());
#endif // __MINGW32__
          }
        break;
      }
    case(Gtk::RESPONSE_CANCEL):
      {
#ifdef DEBUG
        std::cout << "Cancel clicked." << std::endl;
#endif // DEBUG
        break;
      }
    default:
      {
#ifdef DEBUG
        std::cout << "Unexpected button clicked." << std::endl;
#endif // DEBUG
        break;
      }
    }

}

void Png2IcoWindow::on_convert_button_clicked ()
{
  if (dirEntry_.get_text ().empty ())
    {
      Gtk::MessageDialog dialog (*this, "PNG File Directory not specified.", false,
                                 Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
      dialog.set_title ("System");
      dialog.set_secondary_text("This directory is where the PNG file(s) reside.");
      dialog.run();
      return;
    }

  if (outputEntry_.get_text ().empty ())
    {
      Gtk::MessageDialog dialog (*this, "Output directory not specified.", false,
                                 Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
      dialog.set_title ("System");
      dialog.set_secondary_text("This is the directory where the output will be written.");
      dialog.run();
      return;
    }

  if (filenameEntry_.get_text ().empty ())
    {
      Gtk::MessageDialog dialog (*this, "Filename not specified.", false,
                                 Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
      dialog.set_title ("System");
      dialog.set_secondary_text("The filename is the name of the icon file that is produced.");
      dialog.run();
      return;
    }

  // check for PNG file
  bool selected = false;
  typedef Gtk::TreeModel::Children type_children; //minimise code length.
  type_children children = refTreeModel_->children();
  for(type_children::iterator iter = children.begin();
      iter != children.end(); ++iter)
    {
      Gtk::TreeModel::Row row = *iter;
      if (row[columns_.col_use])
        {
          selected = true;
          break;
        }
    }

  if (!selected)
    {
      Gtk::MessageDialog dialog (*this, "No PNG file selected.", false,
                                 Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
      dialog.set_title ("System");
      dialog.set_secondary_text("The selected PNG file(s) will be made into an icon file.");
      dialog.run();
      return;
    }

  std::string cmd = "png2ico ";
  cmd += outputEntry_.get_text ().c_str ();
  std::string pngDir = dirEntry_.get_text ().c_str ();

  vector<std::string> pngFilesList;
  for(type_children::iterator iter = children.begin();
      iter != children.end(); ++iter)
    {
      Gtk::TreeModel::Row row = *iter;
      if (row[columns_.col_use])
        {
          Glib::ustring tmpstr = row[columns_.col_filename];
          pngFilesList.push_back (std::string (tmpstr.c_str ()));
        }
    }

  cmd += "/";
  cmd += filenameEntry_.get_text ().c_str ();
  cmd += " ";
  for (vector<std::string>::iterator iter=pngFilesList.begin (); iter != pngFilesList.end (); iter++)
    {
      cmd += pngDir + "/";
      cmd += *iter + " ";
    }

#ifdef DEBUG
  std::cout << "process file! call png2ico.exe\ncmd: " << cmd << std::endl;
#endif // DEBUG
  system (cmd.c_str ());
}

bool Png2IcoWindow::on_focus_out_event (GdkEventFocus* /*event*/)
{
  std::string file = filenameEntry_.get_text ().c_str ();
  transform (file.begin (), file.end (), file.begin (), tolower);
  size_t found = file.find (".ico");
  Glib::ustring fileStr = filenameEntry_.get_text ();
  if (!fileStr.empty ())
    {
      if (found == std::string::npos)
        {
          fileStr += ".ico";
          filenameEntry_.set_text (fileStr);
        }
    }
  return true;
}

void Png2IcoWindow::on_menu_help_about ()
{
  AboutDialog about;
  about.showDialog (); 
}
